package gagak.framework.web.context;


import gagak.framework.web.annonation.Controller;
import gagak.framework.web.exception.HxWebException;
import gagak.framework.web.handler.ControllerHandler;
import gagak.framework.web.param.HandlerMethod;
import gagak.framework.web.reflect.AnnotationAttributes;
import gagak.framework.web.utils.PkgScanner;
import gagak.framework.web.utils.StringUtils;
import message.Messages;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletContextEvent;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/*
 * @program: ce
 * @description: mvc容器 这是超级重要的容器类，在web 容器启动后
 * 比如tomcat 等启动后，会进行创建一个 MvcApplicationContext 容器
 * 容器会进行收集所有的 HandlerMapping组件，
 * 1：进行url- HandlerMethod 的映射
 * 2：进行 HandlerApater组件的初始化
 * 3：进行 拦截器的创建
 * 4：这里会初始化所有的组件
 * @author: houhong
 * @create: 2022-11-23 20:22
 */
public final class MvcApplica   tionContext extends AbstractApplicationContext {

    private static final Logger logger = LoggerFactory.getLogger(MvcApplicationContext.class);

    /*
     * 获取类加载器
     */
    private static ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

    //默认的扫描路径
    private static String DEFAULT_MVC_SCAN_PATH;

    static {

        Messages msgs = Messages.getInstance();
        Properties prop = msgs.getProperties("mvc.properties");
        //初始化扫描路径
        String basePackage = prop.getProperty("compoentscan.basepackage");

        DEFAULT_MVC_SCAN_PATH = !StringUtils.isEmpty(basePackage)
                ? basePackage : "com";
    }

    /*
     * ur 对应handlerMethod
     */
    private static Map<String, HandlerMethod> urlMappingHandleMap = new HashMap<String, HandlerMethod>();


    /*
     * url和控制器的映射
     */
    private Map<String, ControllerHandler> controllerHandlerMap
            = new ConcurrentHashMap<String, ControllerHandler>(16);

    private ServletContextEvent servletContextEvent;

    public MvcApplicationContext() throws Exception {
        super();
        // 初始化组件
        initApplication();
        //进行url 映射
        innerHandlerMapping();
    }

    public MvcApplicationContext(ServletContextEvent contextEvent) throws Exception {

        servletContextEvent = contextEvent;
        // 初始化组件
        initApplication();
        //进行url 映射
        innerHandlerMapping();
    }


    /*
     * 开始调用handlerMapping进获取所有的url映射
     */
    public final void innerHandlerMapping() throws Exception {

        //做包扫描
        PkgScanner pkgScanner = new PkgScanner(DEFAULT_MVC_SCAN_PATH, Controller.class);

        try {

            List<String> clazzList = pkgScanner.scan();
            logger.info("【mvc-framework】init controller.........\n");
            // className
            for (String className : clazzList) {

                logger.info("【mvc-framework】init controller:name={}", className);
                //类的组装
                ControllerHandler controllerHandler =
                        initControllerHandler(classLoader, className);
                //做handler的组装
                initHandlerMethodInfo(classLoader, className, controllerHandler);

            }
        } catch (IOException e) {
            logger.error("【g5-mvc-framework】 encounter some wrong,pleaser check the pkgScan......\n {}", e);
            throw new HxWebException("package scan error");
        } finally {
        }
    }

    protected ControllerHandler initControllerHandler(ClassLoader classLoader, String className) {

        ControllerHandler controllerHandler = getClassAnnotationInfo(classLoader, className);
        //path
        String path = controllerHandler.getPath();
        //一级映射， 将url -- 和Controlller 对应起来
        controllerHandlerMap.put(path, controllerHandler);

        return controllerHandler;
    }

    /*
     * 二级映射，组合 类上和方法上的url 和HandlerMethod 映射起来
     */
    protected void initHandlerMethodInfo(ClassLoader classLoader, String clazzName, ControllerHandler controllerHandler) throws Exception {

        String controllerPath = controllerHandler.getPath();

        List<HandlerMethod> handlerMethodsInfo = getHandlerMethodsInfo(classLoader, clazzName, controllerHandler);

        for (HandlerMethod handlerMethod : handlerMethodsInfo) {
            //获取一级上面的URl
            String secondURL = handlerMethod.getUrl();
            String url = null;
            if (!secondURL.startsWith("/")) {
                url = controllerPath + "/" + secondURL;
            } else {
                url = controllerPath + secondURL;
            }
            urlMappingHandleMap.put(url, handlerMethod);
        }
    }

    public static Map<String, HandlerMethod> getUrlMappingHandleMap() {
        return urlMappingHandleMap;
    }

    public static void setUrlMappingHandleMap(Map<String, HandlerMethod> urlMappingHandleMap) {
        MvcApplicationContext.urlMappingHandleMap = urlMappingHandleMap;
    }

    public Map<String, ControllerHandler> getControllerHandlerMap() {
        return controllerHandlerMap;
    }

    public void setControllerHandlerMap(Map<String, ControllerHandler> controllerHandlerMap) {
        this.controllerHandlerMap = controllerHandlerMap;
    }

    protected void addClassUrlMapping(AnnotationAttributes attributes) {

        String path = (String) attributes.get("path");


    }


    public final ServletContextEvent getServletContextEvent() {
        return servletContextEvent;
    }

    public void setServletContextEvent(ServletContextEvent servletContextEvent) {
        this.servletContextEvent = servletContextEvent;
    }




}

